/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.model.disc.element;

import java.util.ListIterator;

import br.ufmg.dees.insane.crossSection.CrossSection;
import br.ufmg.dees.insane.model.disc.analysismodel.FrameElmAnalysis;
import br.ufmg.dees.insane.model.disc.fem.FemModel;
import br.ufmg.dees.insane.model.disc.node.Node;
import br.ufmg.dees.insane.model.disc.shape.Cubic1DCart;
import br.ufmg.dees.insane.model.disc.shape.Linear1DCart;
import br.ufmg.dees.insane.model.disc.shape.LinearCubic1DCart;
import br.ufmg.dees.insane.model.disc.shape.Shape;
import br.ufmg.dees.insane.util.IMatrix;
import br.ufmg.dees.insane.util.IPoint3d;
import br.ufmg.dees.insane.util.IVector;

/**
*A class representing a frame element.<p>
*
*The local X axis of a FrameElement is always in the initial node - final node direction.<br>
*The local Y and local Z axis are determined according to this FrameElement's AnalysisModel type.
*
*@author Fonseca, Flavio & Pitangueira, Roque
*@version 1.0
*@since September 2003
*@see CrossSection
*/


public class FrameElement extends Element {
	
	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;

	/** The lenght of this FrameElement.*/
	protected double lenght;
	
	/** The actions at the extremities of this FrameElement.<br>
	* They are stored in this order: <i>Fx1, Fy1, Fz1, Mx1, My1, Mz1, Fx2, Fy2, Fz2, Mx2, My2, Mz2</i>.<br>
	* The actions with the index 1 are related to the initial node and the actions with the index 2 are related to the final node
	*/
	protected double[] actionsAtExtremities = new double[12];
	
	/** The liberations at the extremities of this FrameElement.
	* They are stored in this order: <i>Dx1, Dy1, Dz1, Rx1, Ry1, Rz1, Dx2, Dy2, Dz2, Rx2, Ry2, Rz2</i>.<br>
	* The liberations with the index 1 are related to the initial node and the actions with the index 2 are related to the final node
	*/
	protected boolean[] liberations = new boolean[12];
	
	/** The temperature changes of this FrameElement.
	* They are stored in this order:<p>
	* <i> deltaTemp[0] = temperature change at the top of the cross section. </i><br>
	* <i> deltaTemp[1] = temperature change at the neutral line of this FrameElement. </i><br>
	* <i> deltaTemp[2] = temperature change at the bottom of the cross section. </i>
	*/
	protected double[] deltaTemp = new double [3];
	
	/** The prescribed displacement in this FrameElement.<p>
	* <i><b>It must be informed in this element's nodes' local axis.</b></i><p>
	* They are stored in this order: <br>
	* <i>From 0 to 5 -> Dx, Dy, Dz, Rx, Ry, Rz at the initial Node.</i><br>
	* <i>From 6 to 11 -> Dx, Dy, Dz, Rx, Ry, Rz at the final Node.</i><br>
	*/
	protected IVector elmPreDisplacement = new IVector(12);
	
	/** The initial nodal force vector in this FrameElement.<p>
	* It was include to avoid problems with the user wants to analyse a structure with something
	* which was not implemented.<br>
	* All he have to do is to inform the equivalent nodal force vector for this unexpected analysys.<p>
	* <i><b>It must be informed in this element's local axis.</b></i><p>
	* The data is stored in this order: <br>
	* <i>From 0 to 5 -> Fx, Fy, Fz, Mx, My, Mz at the initial Node.</i><br>
	* <i>From 6 to 11 -> Fx, Fy, Fz, Mx, My, Mz at the final Node.</i><br>
	*/
	protected IVector initialNodalForce = new IVector(12);
	
//********************************************************************************
	
	public FrameElement(){
		equations = new int[12];
	}
	
//********************************************************************************
	
	/** Returns the lenght of this FrameElement.
	*@return The lenght of this FrameElement.
	*/
	public double getLength(){
		return (lenght);
	};
	
	/** Calculates the lenght of this FrameElement.*/
	public void setLenght(){
		IPoint3d point1 = getInitialNode().getCoord();
		IPoint3d point2 = getFinalNode().getCoord();
		lenght = point1.distance(point2);
	};

//********************************************************************************
	
	/** Sets the Shape of this Element, accordingly to the default shape of the Element's AnalysisModel.
	*@param model The model to which this Element belongs.
	*/
	public void setShape(FemModel model) {
		Shape shp;
		FrameElmAnalysis anl = (FrameElmAnalysis) myAnalysisModel;
		String shpClass = anl.getDefaultShapeType();
		boolean foundShape = false;
		ListIterator shps = model.getShapesList().listIterator();
		
		while (shps.hasNext()) {
			shp = (Shape) shps.next();
			if (shp.getType().equals(shpClass)) {
			myShape = shp;
				foundShape = true;
			};
		};
		
		if (!foundShape) {
			
			if (shpClass.equals("LinearCubic1DCart")) {
				shp = new LinearCubic1DCart();
				model.add(shp);
				myShape = shp;
			}
			
			else if (shpClass.equals("Linear1DCart")) {
				shp = new Linear1DCart();
				model.add(shp);
				myShape = shp;
			}
			
			else if (shpClass.equals("Cubic1DCart")) {
				shp = new Cubic1DCart();
				model.add(shp);
				myShape = shp;
			};
			
		};
		
	};
	
//********************************************************************************
	
	/** Returns the action at the extremities of this FrameElement in the specified position.
	*@param a The position of the action at the extremities desired.
	*@return The action at the extremities of this FrameElement in the specified position.
	*/
	public double getActionAtExtremity(int a) {
		return (actionsAtExtremities[a]);
	};
	
	/** Sets the action at the extremities of this FrameElement in the specified position.
	*@param a The position of the action at the extremities desired.
	*@param b The action at the extremities of this FrameElement in the specified position.
	*/
	public void setActionAtExtremity(int a, double b) {
		actionsAtExtremities[a] = b;
	};
	
//********************************************************************************
	
	/** Returns the liberation at the extremities of this FrameElement in the specified position.
	*@param a The position of the desired liberation at the extremities.
	*@return The liberation at the extremities of this FrameElement in the specified position.
	*/
	public boolean getLiberation(int a) {
		return (liberations[a]);
	};
	
	/** Sets the liberation at the extremities of this FrameElement in the specified position.
	*@param a The position of the desired liberation at the extremities.
	*@param b The liberation at the extremities of this FrameElement in the specified position.
	*/
	public void setLiberation(int a, boolean b) {
		liberations[a] = b;
	};
	
//********************************************************************************
	
	/** Returns the temperature change of this FrameElement in the specified position.
	*@param a The position of the desired temperature change.
	*@return The temperature change of this FrameElement in the specified position.
	*/
	public double getDeltaTemp(int a) {
		return (deltaTemp[a]);
	};
	
	/** Sets the temperature change of this FrameElement in the specified position.
	*@param a The position of the desired temperature change.
	*@param b The temperature change of this FrameElement in the specified position.
	*/
	public void setDeltaTemp(int a, double b) {
		deltaTemp[a] = b;
	};
	
//********************************************************************************
	
	/** Returns the initial node of this FrameElement.
	*@return The initial node of this FrameElement.
	*/
	public Node getInitialNode() {
		return ((Node)incidence.get(0));
	};
	
	/** Sets the initial node of this FrameElement.
	*@param a The initial node of this FrameElement.
	*/
	public void setInitialNode(Node a) {
		if (incidence.size() != 0) {
			incidence.remove(0);
			incidence.add(0, a);
		}
		else {
			incidence.add(a);
		};
	};
	
//********************************************************************************
	
	/** Returns the final node of this FrameElement.
	*@return The final node of this FrameElement.
	*/
	public Node getFinalNode() {
		return ((Node)incidence.get(1));
	};
	
	/** Sets the final node of this FrameElement.
	*@param a The final node of this FrameElement.
	*/
	public void setFinalNode(Node a) {
		if (incidence.size() > 1) {
			incidence.remove(1);
			incidence.add(1, a);
		}
		else {
			incidence.add(a);
		};
	};
	
//********************************************************************************
	
	/** Returns the stiffness matrix of this FrameElement in the global coords.
	*@return The stiffness matrix of this FrameElement in the global coords.
	*/
	public IMatrix globalStiffnessMatrix(){
		FrameElmAnalysis anl = (FrameElmAnalysis) myAnalysisModel;
		IMatrix t = anl.transformationMatrix(this);
		IMatrix k = anl.localCorrectedStiffnessMatrix(this);
		IMatrix r = anl.nodalRotationMatrix(this);
		IMatrix aux1 = new IMatrix(r.getNumCol(), t.getNumCol());
		aux1.mulTransposeRight(r, t);
		IMatrix aux2 = new IMatrix(aux1.getNumCol(), k.getNumRow());
		aux2.mul(aux1, k);
		aux1.mul(aux2, t);
		aux2.mulTransposeRight(aux1, r);
		return (aux2);
	};
	
//	********************************************************************************
	
	/** Returns the stiffness matrix of this FrameElement in the global coords.
	*@return The stiffness matrix of this FrameElement in the global coords.
	*/
	/*public IMatrix reduceStiffnessMatrix(){
		StructuralMech sm = new StructuralMech();
    	sm.setFemModel(parent.getView().getController().getModel());
		IMatrix k;
		for (int i=0; i<this.globalStiffnessMatrix().getNumRow(); i++){
			for (int j=0; j<this.globalStiffnessMatrix().getNumCol(); j++){
				if()
			}
		}
	};*/
	
//********************************************************************************
	
	/** Returns the reduced equivalent nodal force vector of this FrameElement in the global coords.
	*@return The reduced equivalent nodal force vector of this FrameElement in the global coords.
	*/
	public IVector globalEquivalentForceVector() {
		FrameElmAnalysis anl = (FrameElmAnalysis) myAnalysisModel;
		IMatrix t = anl.transformationMatrix(this);
		IVector f = anl.localCorrectedEquivalentForceVector(this);
		IMatrix r = anl.nodalRotationMatrix(this);
		IVector aux = new IVector(f.getSize());
		t.transpose();
		aux.mul(t, f);
		IVector aux1 = new IVector(f.getSize());
		aux1.mul(r, aux);
		return(aux1);
	};
	
//********************************************************************************
	
	/** Calculates the internal forces of this FrameElement.<br>
	*In a frame element, the internal forces are the actions at extremities.
	*The displacements of the Nodes must have been previously calculated.
	*/
	public IVector internalForces() {
		int ndf = 2*myAnalysisModel.getNdf();
		FrameElmAnalysis anl = (FrameElmAnalysis) myAnalysisModel;
		IMatrix k = anl.localCorrectedStiffnessMatrix(this);
		IMatrix t = anl.transformationMatrix(this);
		IVector d = new IVector(ndf);
		IVector f = anl.localCorrectedEquivalentForceVector(this);
		IVector aux1 = new IVector(ndf);
		IVector aux2 = new IVector(ndf);
		
		//Setting the values of vector d (nodes displacements)
		Node in = (Node)incidence.get(0);
		Node fn = (Node)incidence.get(1);
		int j = 0;
		for (int i=0; i<6; i++) {
			if (myAnalysisModel.getValidEquation(i)) {
				d.setElement(j, in.getDisplacement(i) + in.getPreDisplacement(i));
				d.setElement(j+ndf/2, fn.getDisplacement(i)  + fn.getPreDisplacement(i));
				j++;
			};
		};
		
		//Making the calculations
		aux1.mul(t, d);
		aux2.mul(k, aux1);
		aux2.sub(f);
		
		//Setting the values of array actionsAtExtremities
		int l = 0;
		for (int i=0; i<12; i++) {
			if (equations[i] != 0) {
				actionsAtExtremities[i] = aux2.getElement(l);
				l++;
			};
		};
		return(new IVector(actionsAtExtremities));
	};
	
//*****************************************************************************
	
	/** Returns this FrameElement's prescribed displacement at the specified position.
	* @param a The position of the desired prescribed displacement.
	* @return The prescribed displacement at the specified position.
	*/
	public double getElmPreDisplacement(int a) {
		return (elmPreDisplacement.getElement(a));
	};
	
	/** Returns this FrameElement's prescribed displacement.
	* @return The prescribed displacement vector.
	*/
	public IVector getElmPreDisplacement() {
		return (elmPreDisplacement);
	};
	
	/** Sets this FrameElement's prescribed displacement at the specified position.
	* @param a The position of the prescribed displacement.
	* @param b The prescribed displacement at the specified position.
	*/
	public void setElmPreDisplacement(int a, double b) {
		elmPreDisplacement.setElement(a, b);
	};
	
//*****************************************************************************
	
	/** Returns this FrameElement's initial nodal force at the specified position.
	* @param a The position of the desired initial nodal force.
	* @return The initial nodal force at the specified position.
	*/
	public double getInitialNodalForce(int a) {
		return (initialNodalForce.getElement(a));
	};
	
	/** Sets this FrameElement's initial nodal force at the specified position.
	* @param a The position of the initial nodal force.
	* @param b The initial nodal force at the specified position.
	*/
	public void setInitialNodalForce(int a, double b) {
		initialNodalForce.setElement(a, b);
	};
	
	/** Returns this FrameElement's initial nodal force vector.
	* @return The initial nodal force vector.
	*/
	public IVector getInitialNodalForceVector() {
		return (initialNodalForce);
	};
	
//*****************************************************************************
	
	/** Sets to zero all the results calculated. */
	public void cleanResults() {
		
		super.cleanResults();
		for (int i=0; i<12; i++)
			actionsAtExtremities[i] = 0;
		
	}
	
//********************************************************************************
}
